#include "net_connection.hpp"
#include "../shared/network.hpp"
#include "ClientPlayer.hpp"
#include <SFML/Network.hpp>

#include <iostream>
#include <vector>
using namespace std;

void Net_Connection::RemoveFromVector(sf::Int32 pid)
{
    for(vector<class ClientPlayer>::iterator iter = this->clients.begin(); iter != this->clients.end(); ++iter)
    {
        if(iter->GetPid() == pid)
        {
            this->clients.erase(iter);
            return;
        }
    }
    throw "No such client";
}

ClientPlayer& Net_Connection::GetClientPlayerByPid(sf::Int32 pid)
{
    for(vector<class ClientPlayer>::iterator iter = this->clients.begin(); iter != this->clients.end(); ++iter)
    {
        if(iter->GetPid() == pid)
        {
            return *iter;
        }
    }
    throw "No such client";
}

void Net_Connection::connect(sf::IPAddress Ip, sf::Uint16 port)
{
    if (this->Sock.Connect(port, Ip) != sf::Socket::Done)
        exit(1);
    //cout << "Connected" << endl;
    sf::Packet Packet;
    if(this->Sock.Receive(Packet) == sf::Socket::Done)
    {
        sf::Uint8 type;
        type = Packet_Type(Packet);
        if(type == PKTYPE_SRV_PLCONNECT)
        {
            this->pid = PK_SRV_PLCONNECT(Packet).pid;
            //cout << "Our Pid is " << this->pid << endl;
        }
    }
    this->Sock.SetBlocking(false);
    this->pos = sf::Vector2f(0,0);
    this->velocity = sf::Vector2f(0,0);
}

void Net_Connection::move(float x, float y)
{
    /*if(x != 0.f || y != 0.f)
    {
        sf::Packet Packet;
        Packet = PK_CLT_PLMOVE(x,y,0.f);
        this->Sock.Send(Packet);
    }*/
    if(x != 0.f || y != 0.f)
    {
        this->update_required = true;
        this->pos.x += x;
        this->pos.y += y;
    }
}

void Net_Connection::rotate(float angle)
{
    /*if(angle != 0)
    {
        sf::Packet Packet;
        Packet = PK_CLT_PLMOVE(0.f,0.f,angle);
        this->Sock.Send(Packet);
    }*/
    if(angle != 0.f)
    {
        this->update_required = true;
        this->angle += angle;
        if(this->angle >= 360)
            this->angle -= 360;
        if(this->angle < 0)
            this->angle += 360;
    }
}

void Net_Connection::receive()
{
    // Wenn Zeit um ist, Pakete senden, aber...
    if(this->wait.GetElapsedTime() > 0.025f && update_required)
    {
        this->wait.Reset();
        update_required = false;
        sf::Packet Packet;
        Packet = PK_CLT_PLMOVE(this->pos.x,this->pos.y,this->velocity.x,this->velocity.y,this->angle);
        this->Sock.Send(Packet);
    }

    // ...immer Pakete empfangen
    sf::Packet Packet;
    if(this->Sock.Receive(Packet) == sf::Socket::Done)
    {
        sf::Uint8 type;
        type = Packet_Type(Packet);
        if(type == PKTYPE_SRV_PLCONNECT)
        {
            ClientPlayer client;
            struct PKCONTENT_SRV_PLCONNECT pkcontent;
            pkcontent = PK_SRV_PLCONNECT(Packet);
            client.SetPid(pkcontent.pid);
            client.pos = sf::Vector2f(0,0);
            client.velocity = sf::Vector2f(0,0);
            client.angle = 0;
            this->clients.push_back(client);

            //cout << "Client connected with PID " << pkcontent.pid << endl;
            return;
        }

        if(type == PKTYPE_SRV_PLDISCONNECT)
        {
            struct PKCONTENT_SRV_PLDISCONNECT pkcontent;
            pkcontent = PK_SRV_PLDISCONNECT(Packet);
            this->RemoveFromVector(pkcontent.pid);

            //cout << "Client disconnected with PID " << pkcontent.pid << endl;
            return;
        }

        if(type == PKTYPE_SRV_PLPOS)
        {
            struct PKCONTENT_SRV_PLPOS pkcontent;
            pkcontent = PK_SRV_PLPOS(Packet);
            if(pkcontent.pid == this->pid)
            {
                this->pos = sf::Vector2f(pkcontent.x,pkcontent.y);
                this->angle = pkcontent.rotation;
                this->velocity = sf::Vector2f(pkcontent.vel_x,pkcontent.vel_y);
                //cout << "Updating own position (" << pkcontent.x << "," << pkcontent.y << ", " << pkcontent.rotation << ")" << endl;
            }
            else
            {
                ClientPlayer& client = this->GetClientPlayerByPid(pkcontent.pid);
                client.pos = sf::Vector2f(pkcontent.x,pkcontent.y);
                client.velocity = sf::Vector2f(pkcontent.vel_x,pkcontent.vel_y);
                client.angle = pkcontent.rotation;
                //cout << "Updating client " << pkcontent.pid << " (" << pkcontent.x << "," << pkcontent.y << ", " << pkcontent.rotation << ")" << endl;
            }
            return;
        }
    }
}

vector<class ClientPlayer> Net_Connection::GetClients()
{
    return this->clients;
}

sf::Int32 Net_Connection::GetPid()
{
    return this->pid;
}
